package org.opentcs.testvehicle;


import com.alibaba.fastjson.JSON;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.order.Route;
import org.opentcs.drivers.vehicle.BasicVehicleCommAdapter;
import org.opentcs.drivers.vehicle.MovementCommand;
import org.opentcs.util.CyclicTask;
import org.opentcs.util.ExplainedBoolean;

import java.util.List;

import static java.util.Objects.requireNonNull;

/*
2.创建一个驱动实现类VehicleCommAdapter(名字随意，我这边用TestCommAdapter)
a.之类为BasicVehicleCommAdapter
b.实现抽象方法
*/
public class TestCommAdapter extends BasicVehicleCommAdapter {

    private final SocketUtils socketUtils;
    private TestAdapterComponentsFactory componentsFactory;
    private Vehicle vehicle;
    private boolean initialized;
    private CyclicTask testTask;

    @Inject
    public TestCommAdapter(TestAdapterComponentsFactory componentsFactory, @Assisted Vehicle vehicle) {
        super(new TestVehicleModel(vehicle), 2, 1, "CHARGE");
        this.componentsFactory = componentsFactory;
        this.vehicle = vehicle;
        String ip = vehicle.getProperty("ip");
        String port = vehicle.getProperty("port");
        this.socketUtils = new SocketUtils(ip, port);
        System.out.println(JSON.toJSONString(socketUtils));
    }

    @Override
    public void initialize() {
        initialized = true;
        //网络通信,获取当前位置，电量，等信息
        //getProcessModel().setVehicleState(Vehicle.State.IDLE);
        //getProcessModel().setVehiclePosition("Point-0001");
    }

    @Override
    public synchronized void enable() {
        if (isEnabled()) {
            return;
        }
        //开启线程(略)
        testTask = new TestTask();
        Thread simThread = new Thread(testTask, getName() + "-Task");
        simThread.start();
        super.enable();
    }

    @Override
    public synchronized void disable() {
        if (!isEnabled()) {
            return;
        }
        //线程停止
        testTask.terminate();
        testTask = null;
        super.disable();
    }

    @Override
    public void sendCommand(MovementCommand cmd)
            throws IllegalArgumentException {
        requireNonNull(cmd, "cmd");
    }

    @Override
    public ExplainedBoolean canProcess(List<String> operations) {
        requireNonNull(operations, "operations");

        final boolean canProcess = isEnabled();
        final String reason = canProcess ? "" : "adapter not enabled";
        return new ExplainedBoolean(canProcess, reason);
    }

    @Override
    public void processMessage(Object message) {
    }

    @Override
    protected void connectVehicle() {

    }

    @Override
    protected void disconnectVehicle() {

    }

    @Override
    protected boolean isVehicleConnected() {
        return true;
    }

    /**
     * 内部类，用于处理运行步骤
     */
    private class TestTask
            extends CyclicTask {

        private TestTask() {
            super(0);
        }

        //线程执行
        @Override
        protected void runActualTask() {
            try {
                //获取状态  位置  速度  方向等
                String str = socketUtils.send("{\"cmd\":\"Read\",\"pathFrom\":\"\",\"pathTo\":\"\"}");
                if (str == null) {
                    Thread.sleep(1000);
                    return;
                }
                if (!str.contains(";")) {
                    Thread.sleep(1000);
                    return;
                }
                // TODO someThings
                String currentPoint = str.split(";")[0];
                String currentStatus = str.split(";")[1];
                getProcessModel().setVehiclePosition(currentPoint);
                if (currentStatus.equals("free")) {
                    getProcessModel().setVehicleState(Vehicle.State.IDLE);
                }
                else if (currentStatus.equals("executing")) {
                    getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
                }


                final MovementCommand curCommand;
                synchronized (TestCommAdapter.this) {
                    curCommand = getSentQueue().peek();
                }
                if (curCommand == null) {
                    Thread.sleep(1000);
                    return;
                }
                final Route.Step curStep = curCommand.getStep();
                simulateMovement(curStep);
                if (!curCommand.isWithoutOperation()) {
                    simulateOperation(curCommand.getOperation());
                }
                if (isTerminated()) {
                    Thread.sleep(1000);
                    return;
                }
                if (getSentQueue().size() <= 1 && getCommandQueue().isEmpty()) {
                    getProcessModel().setVehicleState(Vehicle.State.IDLE);
                }
                synchronized (TestCommAdapter.this) {
                    MovementCommand sentCmd = getSentQueue().poll();
                    if (sentCmd != null && sentCmd.equals(curCommand)) {
                        getProcessModel().commandExecuted(curCommand);
                        TestCommAdapter.this.notify();
                    }
                }
                Thread.sleep(1000);
            }
            catch (Exception ex) {

            }
        }

        private void simulateMovement(Route.Step step) throws Exception{
            if (step.getPath() == null) {
                return;
            }
            Vehicle.Orientation orientation = step.getVehicleOrientation();
            long pathLength = step.getPath().getLength();
            int maxVelocity;
            switch (orientation) {
                case BACKWARD:
                    maxVelocity = step.getPath().getMaxReverseVelocity();
                    break;
                default:
                    maxVelocity = step.getPath().getMaxVelocity();
                    break;
            }
            String pointName = step.getDestinationPoint().getName();
            getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
            String currentPoint = "";
            String currentStatus = "";
            boolean flag = false;
            while (!flag) {
                String str = socketUtils.send("{\"cmd\":\"Path\",\"pathFrom\":\"" + currentPoint + "\",\"pathTo\":\"" + pointName + "\"}");
                if (str.equals("OK")) {
                    flag = true;
                }
                Thread.sleep(1000);
            }

            while (!currentPoint.equals(pointName) && !isTerminated()) {
                String str = socketUtils.send("{\"cmd\":\"Read\",\"pathFrom\":\"\",\"pathTo\":\"\"}");
                if (str == null) {
                    Thread.sleep(1000);
                    continue;
                }
                if (!str.contains(";")) {
                    Thread.sleep(1000);
                    continue;
                }
                currentPoint = str.split(";")[0];
                currentStatus = str.split(";")[1];
                getProcessModel().setVehiclePosition(currentPoint);
                if (currentStatus.equals("free")) {
                    getProcessModel().setVehicleState(Vehicle.State.IDLE);
                }
                else if (currentStatus.equals("executing")) {
                    getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
                }
            }
        }

        private void simulateOperation(String operation) throws Exception{
            requireNonNull(operation, "operation");
            if (isTerminated()) {
                return;
            }
//      getProcessModel().setVehicleState(Vehicle.State.EXECUTING);
//      if (operation.equals(getProcessModel().getLoadOperation())) {
//        //getProcessModel().setVehicleLoadHandlingDevices(Arrays.asList(new LoadHandlingDevice(LHD_NAME, true)));
//      }
//      else if (operation.equals(getProcessModel().getUnloadOperation())) {
//        //getProcessModel().setVehicleLoadHandlingDevices(Arrays.asList(new LoadHandlingDevice(LHD_NAME, false)));
//      }
        }
    }
}
